package com.weilele.mvvm.utils.download

import android.os.Environment
import com.weilele.mvvm.app
import com.weilele.mvvm.utils.net.OkHttpCertUtils
import com.weilele.mvvm.utils.thread.AsyncThread
import okhttp3.*
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.util.concurrent.TimeUnit


/**
 * 描述：利用安卓自带的异步任务处理文件下载
 */
class DownloadHelper {
    /**
     * 文件路径，不带文件名
     */
    private var fileType: String = Environment.DIRECTORY_DOWNLOADS
    private var midPath: String? = null

    /**
     * 默认路径
     * 安卓10，沙盒系统，不支持自定义文件夹
     */
    private fun getPath(): String {
        val file = app.getExternalFilesDir(fileType)
        return if (midPath.isNullOrEmpty()) {
            file!!.path
        } else {
            file!!.path.trimEnd('/') + "/" + midPath!!.trimStart('/')
        }
    }

    /**
     * 文件存在的时候，是否覆盖
     */
    private var isOverlayFile = false

    /**
     * 设置存储路径，不要带上文件名
     * @param type The type of files directory to return. May be {@code null}
     *            for the root of the files directory or one of the following
     *            constants for a subdirectory:
     *            {@link android.os.Environment#DIRECTORY_MUSIC},
     *            {@link android.os.Environment#DIRECTORY_PODCASTS},
     *            {@link android.os.Environment#DIRECTORY_RINGTONES},
     *            {@link android.os.Environment#DIRECTORY_ALARMS},
     *            {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
     *            {@link android.os.Environment#DIRECTORY_PICTURES}, or
     *            {@link android.os.Environment#DIRECTORY_MOVIES}.
     */
    fun setPathType(type: String, midPath: String? = null): DownloadHelper {
        fileType = type
        this.midPath = midPath
        return this
    }

    /**
     * 文件存在的时候是否继续下载替换旧文件
     */
    fun setOverlayFile(overlayFile: Boolean): DownloadHelper {
        isOverlayFile = overlayFile
        return this
    }

    /**
     * 设置存储路径，不要带上文件名
     */
//    fun setSimpleSavePath(path: String): DownloadHelper {
//        filePath = Environment.getExternalStorageDirectory().absolutePath + "/" + path.trimStart('/')
//        return this
//    }

    private lateinit var downloadTask: AsyncThread<String, Long, DownloadBean?>
    private var downloadCall: Call? = null
    fun start(url: String, fileName: String, call: DownListener) {
        downloadTask = AsyncThread(call = call) {
            startDownload(it, fileName, url)
        }
        downloadTask.start(/*filePath ?:*/ getPath())
    }

    fun cancel() {
        downloadCall?.cancel()
        downloadTask.cancel(true)
    }


    /**
     * 开始下载线程
     */
    //文件名需要过滤掉这些字符,不然创建失败
    private val nameFiflt = listOf("?", "*", ":", "\\", "/", "|")

    /**
     * 下载的文件
     */
    private var _downloadFile: File? = null
    val downloadFile: File?
        get() = _downloadFile

    /**
     * 删除下载的文件
     */
    fun deleteDownloadFile() {
        if (downloadFile?.exists() == true) {
            downloadFile?.delete()
        }
    }

    private fun startDownload(
            params: Array<out String>,
            fileName: String,
            url: String
    ): DownloadBean? {
        var fos: FileOutputStream? = null
        var byteStream: InputStream? = null
        val dir = params[0]
        val dirFile = File(dir)
        if (!dirFile.exists()) {
            dirFile.mkdirs()
        }
        var fileNameTemp = fileName.trimStart('/')
        fileNameTemp = fileNameTemp.replace(" ", "")
        nameFiflt.forEach {
            fileNameTemp = fileNameTemp.replace(it, "_")
        }
        val path = dir.trimEnd('/') + "/" + fileNameTemp
        val file = File(path)
        _downloadFile = file
        try {
            if (file.exists()) {
                if (isOverlayFile) {
                    file.delete()
                } else {
                    return DownloadBean(fileName, url, file, path, file.length(), false)
                }
            }
            val client =OkHttpCertUtils.createCertOkHttpBuilder()
                    .readTimeout(5, TimeUnit.MINUTES)
                    .writeTimeout(5, TimeUnit.MINUTES)
                    .connectTimeout(5, TimeUnit.MINUTES)
                    .addNetworkInterceptor { chain ->
                        val originalResponse = chain.proceed(chain.request())
                        originalResponse.newBuilder()
                                .body(ProgressResponseBody(originalResponse.body!!) {
                                    downloadTask.onError(it)
                                    cancel()
                                })
                                .build()
                    }
                    .build()
            val downRequest = Request.Builder()
                    .url(url)
                    .build()
            downloadCall = client.newCall(downRequest)
            val response = downloadCall?.execute()
            if (response?.code != 200) {
                downloadTask.onError(Throwable("httpError:code:${response?.code},message:${response?.message}"))
                cancel()
                return null
            }
            byteStream = response.body?.byteStream()!!
            val total = response.body?.contentLength()!!
            fos = FileOutputStream(file)
            var len: Int
            val buf = ByteArray(1024)
            var downloadSize = 0L
            while (byteStream.read(buf).apply { len = this } > 0) {
                fos.write(buf, 0, len)
                downloadSize += len
                downloadTask.setProgress(downloadSize, total, downloadSize * 100 / total)
            }
            return DownloadBean(fileName, url, file, path, total, true)
        } catch (e: Throwable) {
            if (file.exists()) {
                file.delete()
            }
            e.printStackTrace()
            return null
        } finally {
            byteStream?.close()
            fos?.flush()
            fos?.close()
        }
    }


}